/*
 * ===========================================================================
 *
 *      Filename: mem_pool.c
 *   Description: memory pool
 *        Author: Ye wenhao, wenhaoye@126.com
 *  Organization: 
 *
 * ===========================================================================
 */
#include "mem_pool.h"


/*************************************************************************
*                   mem unit operation
************************************************************************/
inline static void *mu_create(mem_unit_t *self)
{
	return self->create(self);
}

inline static int mu_destroy(mem_unit_t *self, void *p)
{
	return self->destroy(self, p);
}

inline static void mu_release(mem_unit_t *self)
{
	if (self->release) {
		return self->release(self);
	}
}

inline static uint32_t mu_size(mem_unit_t *self)
{
	return self->size;
}

inline static uint32_t mu_total(mem_unit_t *self)
{
	return self->total;
}


/**************************************************************************
*              wrapper for mem pool
*************************************************************************/
inline static void *mp_create_mu(mem_pool_t *self)
{
	return mu_create(self->mu);
}

inline static int mp_destroy_mu(mem_pool_t *self, void *p)
{
	return mu_destroy(self->mu, p);
}

inline static void mp_release_mu(mem_pool_t *self)
{
	return mu_release(self->mu);
}

inline static uint32_t mp_get_mu_size(mem_pool_t *self)
{
	return mu_size(self->mu);
}

inline static uint32_t mp_get_mu_total(mem_pool_t *self)
{
	return mu_total(self->mu);
}

inline static int mp_lock(mem_pool_t *self)
{
	return locker_lock(self->locker);
}

inline static int mp_unlock(mem_pool_t *self)
{
	return locker_unlock(self->locker);
}

/******************************************************************************
*                        memory pool 
*****************************************************************************/
int mem_pool_init(mem_pool_t *self, locker_t *locker)
{
	if (!self->mu || !self->mu->create || !self->mu->destroy) {
		DBG("invalid mu");
		return -1;
	}

	self->unit_nums = 0;
	dl_list_init(&self->list);
	self->locker = locker;
	uint32_t total = mp_get_mu_total(self);

	uint32_t i;
	void *node;
	for(i = 0; i < total; ++i){
		node = mp_create_mu(self);
		if(node == NULL){
			mem_pool_term(self);
			return -1;
		}

		dl_list_add_tail(&self->list, (struct dl_list *)node);
		self->unit_nums++;
	}

	return 0;
}

void mem_pool_term(mem_pool_t *self)
{
	struct dl_list *item;
	struct dl_list *n;

	mp_lock(self);
	dl_list_for_each_safe(item, n, &self->list){
		dl_list_del(item);
		mp_destroy_mu(self, (void *)item);
		self->unit_nums--;
	}
	mp_unlock(self);

	mp_release_mu(self);
	locker_destroy(self->locker);
}


void *mem_unit_get(mem_pool_t *self)
{
	if(!self)
		return NULL;

	void *ptr = NULL;
	struct dl_list *item;

	mp_lock(self);
	if(self->unit_nums > 0){
		item = self->list.next;
		dl_list_del(item);
		ptr = (void *)item;
		self->unit_nums--;
	}else{
		ptr = mp_create_mu(self);
	}
	mp_unlock(self);

	return ptr;
}

int mem_unit_put(mem_pool_t *self, void *ptr)
{
	if(!self || !ptr)
		return -1;

	struct dl_list *item = (struct dl_list *)ptr;

	mp_lock(self);
	if(self->unit_nums < mp_get_mu_total(self)){
		dl_list_add_tail(&self->list, item);
		self->unit_nums++;
	}else{
		mp_destroy_mu(self, ptr);
	}
	mp_unlock(self);

	return 0;
}
